home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / dvipage / dvipage.c < prev    next >
C/C++ Source or Header  |  1992-05-11  |  49KB  |  2,422 lines

  1. /*
  2.  * dvipage: DVI Previewer Program for Suns
  3.  *
  4.  * Neil Hunt (hunt@spar.slb.com)
  5.  *
  6.  * This program is based, in part, upon the program dvisun,
  7.  * distributed by the UnixTeX group, extensively modified by
  8.  * Neil Hunt at the Schlumberger Palo Alto Research Laboratories
  9.  * of Schlumberger Technologies, Inc.
  10.  *
  11.  * From the dvisun manual page entry:
  12.  *    Mark Senn wrote the early versions of [dvisun] for the
  13.  *    BBN BitGraph. Stephan Bechtolsheim, Bob Brown, Richard
  14.  *    Furuta, James Schaad and Robert Wells improved it. Norm
  15.  *    Hutchinson ported the program to the Sun. Further bug fixes
  16.  *    by Rafael Bracho at Schlumberger.
  17.  *
  18.  * Copyright (c) 1988 Schlumberger Technologies, Inc 1988.
  19.  * Anyone can use this software in any manner they choose,
  20.  * including modification and redistribution, provided they make
  21.  * no charge for it, and these conditions remain unchanged.
  22.  *
  23.  * This program is distributed as is, with all faults (if any), and
  24.  * without any warranty. No author or distributor accepts responsibility
  25.  * to anyone for the consequences of using it, or for whether it serves any
  26.  * particular purpose at all, or any other reason.
  27.  *
  28.  * $Log:    dvipage.c,v $
  29.  * Revision 1.6  88/12/15  09:08:03  hunt
  30.  * Added iteration to gobble inputs in panning and magnifier.
  31.  * 
  32.  * Revision 1.5  88/11/28  18:39:21  hunt
  33.  * Major rewrite for 4.0 and sparc architecture.
  34.  * Split up into multiple files for easier maintenance.
  35.  * Reads GF files as well as PXL files now.
  36.  * 
  37.  * Revision 1.4  88/11/26  11:10:53  hunt
  38.  * Used varargs with *_prompt() functions for correct behaviour on a sun4.
  39.  * 
  40.  * Revision 1.3  88/08/30  13:04:13  hunt
  41.  * Changed default cmap for darker looking letters.
  42.  * 
  43.  * Revision 1.2  88/08/30  09:26:29  hunt
  44.  * Fixed problem pointed out by pell@rainier.UUCP
  45.  * (pell@rainier.se, enea!rainier!pell@uunet.UU.NET)
  46.  * so that opened files are closed on exec, and do not clutter up
  47.  * space in print spoolers which may be invoked
  48.  * to print the document.
  49.  * 
  50.  * Revision 1.1  88/08/30  09:05:19  hunt
  51.  * Initial revision
  52.  * 
  53.  * HISTORY
  54.  *
  55.  * 12 April 1988 - Neil Hunt
  56.  *    Version 2.0 released for use.
  57.  *
  58.  * 11 April 1988 - Neil Hunt
  59.  *    Applied fixes supplied by Rafael Bracho (Schlumberger Austin)
  60.  *    for operation on Sun-4 workstations.
  61.  *
  62.  * Earlier history unavailable.
  63.  */
  64.  
  65. #include <stdio.h>
  66. #include <strings.h>
  67. #include <fcntl.h>
  68. #include <sys/ioctl.h>
  69. #include <varargs.h>
  70. #include <sys/param.h>        /* For MAXPATHLEN */
  71. #include <sys/stat.h>
  72. #include <suntool/sunview.h>
  73. #include <suntool/canvas.h>
  74. #include <suntool/panel.h>
  75. #include <suntool/icon.h>
  76. #include "dvipage.h"
  77. #include "dvi.h"
  78.  
  79. #define GOBBLE_PAN
  80. #define GOBBLE_MAGNIFY
  81.  
  82. /*
  83.  * Forward functions.
  84.  * =================
  85.  */
  86.  
  87. forward int            main();
  88.  
  89. forward Notify_value        page_paint();
  90. forward Notify_value        page_event();
  91. forward int            page_menu();
  92. forward void            page_magnify();
  93. forward void            page_pan();
  94. forward bool            goto_sheet();
  95. forward bool            goto_page();
  96.  
  97. forward bool            init_dvi_file();
  98. forward void            close_dvi_file();
  99. forward bool            check_dvi_file();
  100.  
  101. forward bool            read_postamble();
  102. forward bool            find_postamble_ptr();
  103.  
  104. forward bool            process_page();
  105.  
  106. forward void            set_font_num();
  107. forward void            set_char();
  108. forward void            set_rule();
  109. forward void            move_down();
  110. forward void            move_over();
  111.  
  112. forward char *            a_prog_name;
  113. forward char            a_next();
  114. forward char *            a_arg();
  115. forward double            a_number();
  116. forward int            a_integer();
  117.  
  118. /*
  119.  * Internal data structures.
  120.  * ========================
  121.  */
  122.  
  123. struct stack_entry        /* stack entry */
  124. {
  125.     int h, v, w, x, y, z;  /* what's on stack */
  126. };
  127.  
  128. /*
  129.  * Globals.
  130.  * =======
  131.  */
  132.  
  133. int hconv, vconv;        /* converts DVI units to pixels */
  134. int num;            /* numerator specified in preamble */
  135. int den;            /* denominator specified in preamble */
  136. int mag;            /* magnification specified in preamble */
  137.  
  138. struct font_entry *fontptr;     /* font_entry pointer */
  139. struct font_entry *hfontptr=NULL;/* font_entry pointer */
  140.  
  141. double page_w = PAGE_WIDTH;    /* page width (inches) */
  142. double page_h = PAGE_HEIGHT;    /* page width (inches) */
  143.  
  144. int h;                /* current horizontal position */
  145. int hh;                /* current horizontal position in pixels */
  146. int v;                /* current vertical position */
  147. int vv;                /* current vertical position in pixels */
  148.  
  149. bool pre_load = TRUE;        /* preload the font descriptions? */
  150. bool silent = FALSE;        /* suppress messages */
  151. bool show_page_frame = FALSE;    /* show page window */
  152.  
  153. long postambleptr;        /* Pointer to the postamble */
  154.  
  155. char *font_path;        /* Font path name for search */
  156. bool use_gf = USE_GF;        /* Enable the use of GF fonts. */
  157. bool use_pxl = USE_PXL;        /* Enable the use of PXL fonts. */
  158. bool use_pk = USE_PK;        /* Enable the use of PK fonts. */
  159.  
  160. FILE *dvifp = NULL;        /* File pointer */
  161.  
  162. struct stat stat_buf;        /* For checking file changes. */
  163. time_t mtime = 0;
  164.  
  165. char label[STRSIZE];
  166.  
  167. char pathname[STRSIZE] = "";    /* Complete path */
  168. char directory[STRSIZE] = "";    /* Directory */
  169. char filename[STRSIZE] = "";    /* File name */
  170. char print_spooler[STRSIZE] = PRINT_SPOOLER;    /* Print commands. */
  171. char print_page_spooler[STRSIZE] = PRINT_PAGE_SPOOLER;
  172.  
  173. int last_sheet = 0;        /* Sheet number of last page in file */
  174. int file_sheet = 1;        /* Position of file pointer */
  175. int disp_sheet = 0;        /* Current displayed page */
  176. int disp_page = 0;        /* Real Page number */
  177. int sheet_page[MAX_SHEETS];    /* Page number of each sheet. */
  178. long sheet_table[MAX_SHEETS];    /* pointers to start of each page in file */
  179. int last_known_sheet = 0;    /* Points to table at next unread sheet */
  180.  
  181. int resolution = 0;        /* Assumed screen resolution for rendering */
  182. int sampling = 0;        /* Sample down sampling factor */
  183. bool mono;            /* Monochrome screen */
  184.  
  185. Frame disp_frame;        /* Frame for display window. */
  186. Canvas disp_canvas;        /* Canvas for display window. */
  187.  
  188. struct mem_pixrect page_mpr;    /* Page bitmap. */
  189. struct pixrect *page_pr;
  190. struct mem_pixrect sample_mpr;    /* Sampled/filtered bitmap. */
  191. struct pixrect *sample_pr;
  192.  
  193. int origin_x;            /* Nominal origin of the dvi on the page */
  194. int origin_y;            /* Nominal origin of the dvi on the page */
  195.  
  196. int offset_x;            /* Offsets of page in window. */
  197. int offset_y;            /* Offsets of page in window. */
  198.  
  199. int start_x;            /* Starting position of page in the window */
  200. int start_y;            /* Starting position of page in the window */
  201.  
  202. int verbose;            /* Flags for debugging. */
  203.  
  204. int mag_size_x = DEFAULT_MAG_SIZE_X;    /* Magnifier parameters. */
  205. int mag_size_y = DEFAULT_MAG_SIZE_Y;
  206. int mag_border = DEFAULT_MAG_BORDER;
  207.  
  208. forward uchar cmap_red[];
  209. forward uchar cmap_green[];
  210. forward uchar cmap_blue[];
  211.  
  212. short icon_image[] =
  213. {
  214. /* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16
  215.  */
  216.     0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x8000,0x0000,0x0000,0x0001,
  217.     0x8000,0x0000,0x0000,0x0001,0x8000,0x0000,0x0000,0x0001,
  218.     0x8000,0x0000,0x00C0,0x0001,0x8000,0x0000,0x0338,0x0001,
  219.     0x8000,0x0000,0x0447,0x0001,0x8000,0x0000,0x1911,0xE001,
  220.     0x8000,0x0000,0x2888,0x9E01,0x8000,0x0000,0xC222,0x23C1,
  221.     0x8000,0x0001,0x4444,0x4479,0x8000,0x0007,0x1111,0x1117,
  222.     0x8000,0x0008,0x8888,0x8889,0x8000,0x0032,0x2222,0x2223,
  223.     0x8000,0x0044,0x4444,0x4445,0x8000,0x0191,0x1111,0x1111,
  224.     0x8000,0x0288,0x8888,0x888B,0x8000,0x0C22,0x2222,0x2225,
  225.     0x8000,0x1444,0x4444,0x4447,0x8000,0x6111,0x1111,0x1119,
  226.     0x8000,0xC888,0x8888,0x889B,0x8000,0xB222,0x2222,0x2235,
  227.     0x8000,0xCE44,0x4444,0x446B,0x8000,0x91D1,0x1111,0x11D5,
  228.     0x8000,0x88B8,0x8888,0x88AB,0x8000,0xAC2E,0x2222,0x2355,
  229.     0x8000,0xC345,0xC444,0x46AB,0x8000,0x9CD1,0x3111,0x1555,
  230.     0x8000,0xB338,0x8E88,0x8AA5,0x8000,0xE0C6,0x23E2,0x3559,
  231.     0x8000,0xC039,0x8474,0x56B1,0x8000,0xC006,0x611F,0x2D41,
  232.     0x8000,0x9001,0x9C89,0xDEA1,0x8001,0x0C00,0x6322,0xFD41,
  233.     0x8002,0x43E0,0x1CC4,0xBE81,0x8004,0x2C18,0x0331,0xFD01,
  234.     0x8008,0x3606,0x00C8,0xBB01,0x8031,0xC781,0x0032,0xF601,
  235.     0x8040,0x4CC1,0x0014,0xAC01,0x818C,0x9840,0xC021,0xD801,
  236.     0x8602,0xB208,0xB048,0xA801,0x9861,0x6788,0x4CC2,0xD001,
  237.     0xB011,0xCCD9,0xC0C4,0xA001,0xA30D,0x1817,0x60B1,0xC001,
  238.     0x9883,0x3E1C,0x590E,0xC001,0x8463,0x6270,0x4101,0x8001,
  239.     0x821F,0xC1D0,0xC100,0x0001,0x813F,0xB310,0xB200,0x0001,
  240.     0x81FC,0x5831,0x0200,0x0001,0x87F8,0x4021,0x0400,0x0001,
  241.     0x9F8C,0x3006,0xC400,0x0001,0x9E07,0x0C18,0x0800,0x0001,
  242.     0x8C00,0x83E8,0x1000,0x0001,0x8000,0x6106,0x2000,0x0001,
  243.     0x8000,0x18C0,0x4000,0x0001,0x8000,0x0430,0x8000,0x0001,
  244.     0x8000,0x0309,0x0000,0x0001,0x8000,0x0081,0x0000,0x0001,
  245.     0x8000,0x0062,0x0000,0x0001,0x8000,0x0014,0x0000,0x0001,
  246.     0x8000,0x0008,0x0000,0x0001,0x8000,0x0000,0x0000,0x0001,
  247.     0x8000,0x0000,0x0000,0x0001,0xFFFF,0xFFFF,0xFFFF,0xFFFF
  248. };
  249.  
  250. DEFINE_ICON_FROM_IMAGE(icon, icon_image);
  251.  
  252. short hand[] =
  253. {
  254.   0x0C00,0x1200,0x1200,0x1380,0x1240,0x7270,0x9248,0x924E,
  255.   0x9249,0x9249,0x9009,0x8001,0x4002,0x4002,0x2004,0x2004
  256. };
  257. mpr_static(hand_pr, 16, 16, 1, hand);
  258. Cursor hand_cursor;
  259.  
  260. /*
  261.  * Functions.
  262.  * =========
  263.  */
  264.  
  265. /*
  266.  * main:
  267.  *    Interpret args, open windows, loop forever.
  268.  */
  269.  
  270. int
  271. main(argc, argv)
  272. int argc;
  273. char *argv[];
  274. {
  275.     int f;
  276.     char opt;
  277.     char *slash;
  278.     char *extension;
  279.     Pixwin *pw;
  280.     bool fake_mono;
  281.     char *printer;
  282.     double set_origin_x;
  283.     double set_origin_y;
  284.     double set_start_x;
  285.     double set_start_y;
  286.  
  287.     /*
  288.      * local initialisations.
  289.      */
  290.     fake_mono = FALSE;
  291.     set_origin_x = 0.0;
  292.     set_origin_y = 0.0;
  293.     set_start_x = 0.0;
  294.     set_start_y = 0.0;
  295.  
  296.     /*
  297.      * Customise this part for your local printer environment.
  298.      * ======================================================
  299.      */
  300. #ifdef SPAR_HACKS
  301.  
  302.     /*
  303.      * Set local printer hacks.
  304.      */
  305.     printer = getenv("PRINTER");
  306.     if(printer && strncmp(printer, "lw", 2) == 0)
  307.     {
  308.         sprintf(print_spooler,
  309.           "dvips -P%s %%s >/dev/null 2>/dev/null",
  310.           printer);
  311.         sprintf(print_page_spooler,
  312.           "dvips -P%s -f %%d -t %%d %%s >/dev/null 2>/dev/null",
  313.           printer);
  314.     }
  315.     else if(printer && strncmp(printer, "im", 2) == 0)
  316.     {
  317.         sprintf(print_spooler,
  318.           "dviimp -P%s %%s >/dev/null 2>/dev/null",
  319.           printer);
  320.         sprintf(print_page_spooler,
  321.           "dviimp -P%s -S %%d -E %%d %%s >/dev/null 2>/dev/null",
  322.           printer);
  323.     }
  324.     else
  325.     {
  326.         fprintf(stderr, "PRINTER environment not recognised:\n");
  327.         fprintf(stderr, " using `%s' to print files\n",
  328.           print_spooler);
  329.         fprintf(stderr, " using `%s' to print pages\n",
  330.           print_page_spooler);
  331.     }
  332.  
  333.     if(verbose & DEBUG_PRINTER)
  334.     {
  335.         fprintf(stderr, "Using `%s' to print files\n",
  336.           print_spooler);
  337.         fprintf(stderr, "Using `%s' to print pages\n",
  338.           print_page_spooler);
  339.     }
  340.  
  341. #endif SPAR_HACKS
  342.  
  343.     /*
  344.      * Find font path environment.
  345.      */
  346.     if((font_path = getenv(FONT_PATH)) == NULL)
  347.         font_path = FONT_AREA;
  348.  
  349.     /*
  350.      * Get cursor.
  351.      */
  352.     hand_cursor = cursor_create(
  353.       CURSOR_IMAGE, &hand_pr,
  354.       CURSOR_XHOT, 5,
  355.       CURSOR_YHOT, 0,
  356.       CURSOR_OP, PIX_SRC ^ PIX_DST,
  357.       0);
  358.  
  359.     /*
  360.      * Create a disp_frame.
  361.      */
  362.     disp_frame = window_create(0, FRAME,
  363.       WIN_X, 300,
  364.       WIN_Y, 50, 
  365.       WIN_WIDTH,
  366.         (int)(page_w * DEFAULT_COLOUR_RES /
  367.            DEFAULT_COLOUR_SAMPLING) + 10,
  368.       WIN_HEIGHT,
  369.         (int)(page_h * DEFAULT_COLOUR_RES /
  370.            DEFAULT_COLOUR_SAMPLING) + 20,
  371.       FRAME_ARGC_PTR_ARGV, &argc, argv,
  372.       FRAME_LABEL, DVIPAGE_LABEL,
  373.       FRAME_ICON, &icon,
  374.       0);
  375.  
  376.     /*
  377.      * Create the disp_canvas.
  378.      */
  379.     disp_canvas = window_create(disp_frame, CANVAS,
  380.       CANVAS_RETAINED, FALSE,
  381.       CANVAS_AUTO_CLEAR, FALSE,
  382.       CANVAS_FIXED_IMAGE, TRUE,
  383.       WIN_CURSOR, hand_cursor,
  384.       WIN_CONSUME_PICK_EVENTS,
  385.         WIN_NO_EVENTS,
  386.         LOC_DRAG,
  387.         WIN_MOUSE_BUTTONS,
  388.         LOC_WINENTER,    /* Otherwise misses first event */
  389.         LOC_WINEXIT,
  390.         0,
  391.       WIN_CONSUME_KBD_EVENTS,
  392.         WIN_NO_EVENTS,
  393.         WIN_ASCII_EVENTS,
  394.         WIN_LEFT_KEYS,    /* For Expose, Hide, Close etc. */
  395.         KBD_USE,        /* Otherwise click to type doesn't work */
  396.         KBD_DONE,
  397.         0,
  398.       CANVAS_REPAINT_PROC, page_paint,
  399.       WIN_EVENT_PROC, page_event,
  400.       WIN_WIDTH, WIN_EXTEND_TO_EDGE,
  401.       WIN_HEIGHT, WIN_EXTEND_TO_EDGE,
  402.       0);
  403.  
  404.     /*
  405.      * Interpret args.
  406.      */
  407.     f = 0;
  408.     while((opt = a_next(argc, argv)) != A_END)
  409.     {
  410.         switch(opt)
  411.         {
  412.         default:
  413.             fprintf(stderr, "%s: illegal flag -%c\n",
  414.               a_prog_name, opt);
  415.             /* FALLTHROUGH */
  416.         case 'H':
  417.             fprintf(stderr,
  418.   "Usage: %s \\\n", a_prog_name);
  419.             fprintf(stderr,
  420.   "    [-v mode]        # Verbose mode (for debugging) \\\n");
  421.             fprintf(stderr,
  422.   "    [-m]            # Force monochrome mode \\\n");
  423.             fprintf(stderr,
  424.   "    [-p font-file-path]    # List of font directories \\\n");
  425.             fprintf(stderr,
  426.   "    [-P flag]        # Enable or disable the use of PXL files \\\n");
  427.             fprintf(stderr,
  428.   "    [-K flag]        # Enable or disable the use of PK files \\\n");
  429.             fprintf(stderr,
  430.   "    [-G flag]        # Enable or disable the use of GF files \\\n");
  431.             fprintf(stderr,
  432.   "    [-l]            # Don't preload font data \\\n");
  433.             fprintf(stderr,
  434.   "    [-q]            # Quiet: no warning messages \\\n");
  435.             fprintf(stderr,
  436.   "    [-f]            # Show rendering frame on page \\\n");
  437.             fprintf(stderr,
  438.   "    [-r res]        # Use `res' dpi fonts \\\n");
  439.             fprintf(stderr,
  440.   "    [-s sample]        # Reduce by factor of `sample' \\\n");
  441.             fprintf(stderr,
  442.   "    [-x x] [-y y]        # Initial pos of sheet in inches \\\n");
  443.             fprintf(stderr,
  444.   "    [-X ox] [-Y oy]        # Pos of (0, 0) on page in inches \\\n");
  445.             fprintf(stderr,
  446.   "    [-w width] [-h height]    # Total size of page in inches \\\n");
  447.             fprintf(stderr,
  448.   "    [dvifile[.dvi]]\n");
  449.             exit(1);
  450.  
  451.         case 'v':
  452.             verbose = a_integer(argc, argv);
  453.             break;
  454.  
  455.         case 'm':
  456.             fake_mono = TRUE;
  457.             break;
  458.  
  459.         case 'p':
  460.             font_path = a_arg(argc, argv);
  461.             break;
  462.  
  463.         case 'P':
  464.             use_pxl = a_integer(argc, argv);
  465.             break;
  466.  
  467.         case 'K':
  468.             use_pk = a_integer(argc, argv);
  469.             break;
  470.  
  471.         case 'G':
  472.             use_gf = a_integer(argc, argv);
  473.             break;
  474.  
  475.         case 'l':
  476.             pre_load = ! pre_load;
  477.             break;
  478.  
  479.         case 'q':
  480.             silent = ! silent;
  481.             break;
  482.  
  483.         case 'f':
  484.             show_page_frame = ! show_page_frame;
  485.             break;
  486.  
  487.         case 'r':
  488.             resolution = a_integer(argc, argv);
  489.             break;
  490.  
  491.         case 's':
  492.             sampling = a_integer(argc, argv);
  493.             break;
  494.  
  495.         case 'x':
  496.             set_start_x = a_number(argc, argv);
  497.             break;
  498.  
  499.         case 'y':
  500.             set_start_y = a_number(argc, argv);
  501.             break;
  502.  
  503.         case 'X':
  504.             set_origin_x = a_number(argc, argv);
  505.             break;
  506.  
  507.         case 'Y':
  508.             set_origin_y = a_number(argc, argv);
  509.             break;
  510.  
  511.         case 'w':
  512.             page_w = a_number(argc, argv);
  513.             break;
  514.  
  515.         case 'h':
  516.             page_h = a_number(argc, argv);
  517.             break;
  518.  
  519.         case A_ARG:
  520.             switch(f++)
  521.             {
  522.             case 0:
  523.                 /*
  524.                  * Get the whole pathname.
  525.                  */
  526.                 strcpy(pathname, a_arg(argc, argv));
  527.  
  528.                 /*
  529.                  * Get the filename and directory
  530.                  */
  531.                 strcpy(directory, pathname);
  532.                 if((slash = rindex(directory, '/')) != NULL)
  533.                 {
  534.                     strcpy(filename, slash+1);
  535.                     *++slash = '\0';
  536.                 }
  537.                 else
  538.                 {
  539.                     directory[0] = '\0';
  540.                     strcpy(filename, pathname);
  541.                 }
  542.  
  543.                 /*
  544.                  * If the filename has no extension, or if it
  545.                  * has an extension and it is not '.dvi' then
  546.                  * cat .dvi onto the filename.
  547.                  */
  548.                 if((extension = rindex(pathname, '.')) == NULL ||
  549.                   strcmp(extension, ".dvi") != 0)
  550.                     strcat(pathname, ".dvi");
  551.  
  552.                 break;
  553.  
  554.             default:
  555.                 fprintf(stderr,
  556.   "%s: too many dvi files\n", a_prog_name);
  557.                 exit(1);
  558.             }
  559.             break;
  560.         }
  561.     }
  562.  
  563.     pw = canvas_pixwin(disp_canvas);
  564.  
  565.     /*
  566.      * Now that we know whether we are on a colour machine or a monochrome,
  567.      * we can set the defaults for the resolution and sampling, unless
  568.      * they have already been set from the args.
  569.      */
  570.     if(fake_mono || (pw->pw_pixrect->pr_depth == 1))
  571.     {
  572.         /*
  573.          * Monochrome
  574.          */
  575.         mono = TRUE;
  576.  
  577.         if(resolution == 0)
  578.             resolution = DEFAULT_MONO_RES;
  579.         if(sampling == 0)
  580.             sampling = DEFAULT_MONO_SAMPLING;
  581.     }
  582.     else
  583.     {
  584.         /*
  585.          * Colour
  586.          */
  587.         mono = FALSE;
  588.  
  589.         if(resolution == 0)
  590.             resolution = DEFAULT_COLOUR_RES;
  591.         if(sampling == 0)
  592.             sampling = DEFAULT_COLOUR_SAMPLING;
  593.  
  594.         /*
  595.          * Compute and set a colour map
  596.          */
  597.         make_cmap();
  598.         pw_setcmsname(pw, "dvipage-greys");
  599.         pw_putcolormap(pw, 0, 64, cmap_red, cmap_green, cmap_blue);
  600.     }
  601.  
  602.     /*
  603.      * Now that we know the resolution and sampling, we can set
  604.      * the margin and origin properly.
  605.      */
  606.     if(set_origin_x != 0.0)
  607.         origin_x = (int)(set_origin_x * resolution);
  608.     else
  609.         origin_x = (int)(DEFAULT_ORIGIN_X * resolution);
  610.  
  611.     if(set_origin_y != 0.0)
  612.         origin_y = (int)(set_origin_y * resolution);
  613.     else
  614.         origin_y = (int)(DEFAULT_ORIGIN_Y * resolution);
  615.  
  616.     if(set_start_x != 0.0)
  617.         start_x = (int)(set_start_x * resolution);
  618.     else
  619.         start_x = (int)(DEFAULT_START_X * resolution);
  620.  
  621.     if(set_start_y != 0.0)
  622.         start_y = (int)(set_start_y * resolution);
  623.     else
  624.         start_y = (int)(DEFAULT_START_Y * resolution);
  625.  
  626.     /*
  627.      * Insert the window into the heap now, so that if a message is
  628.      * generated by the init_dvi_file below, it is displayed after the
  629.      * window, and is therefore on top of it. If we display the window
  630.      * after doing the initialisation of the dvi file, it would obscure
  631.      * any error messages which might have been generated.
  632.      */
  633.     window_set(disp_frame,
  634.       WIN_SHOW, TRUE,
  635.       0);
  636.  
  637.     /*
  638.      * If we don't run the notifier at this time, the window will
  639.      * not be painted, and the effect will be a gross area of the
  640.      * screen which is not painted, through which the previous windows
  641.      * are still visible.
  642.      */
  643.     notify_dispatch();
  644.  
  645.     /*
  646.      * If there was a filename specified, then open it
  647.      * and prepare the first page.
  648.      */
  649.     if(f >= 1)
  650.     {
  651.         /*
  652.          * Init the file.
  653.          */
  654.         if(init_dvi_file())
  655.         {
  656.             process_page(RASTERISE);
  657.             offset_x = start_x / sampling;
  658.             offset_y = start_y / sampling;
  659.             page_paint(disp_canvas, pw, 0);
  660.         }
  661.     }
  662.     else
  663.         getwd(directory);
  664.  
  665.     /*
  666.      * Loop forever in the notifier.
  667.      */
  668.     notify_start();
  669. }
  670.  
  671. /*
  672.  * Window Functions.
  673.  * ================
  674.  */
  675.  
  676. /*
  677.  * page_paint:
  678.  *    Called whenever the window is to be painted.
  679.  *    Just maps the sampled pixrect into the screen at the appropriate
  680.  *    offset position.
  681.  */
  682.  
  683. Notify_value
  684. page_paint(canvas, pw, area)
  685. Canvas canvas;
  686. Pixwin *pw;
  687. Rectlist *area;
  688. {
  689.     if(sample_pr == NULL)
  690.     {
  691.         pw_rop(pw, 0, 0,
  692.           (int)window_get(canvas, WIN_WIDTH),
  693.           (int)window_get(canvas, WIN_HEIGHT),
  694.           PIX_CLR, NULL, 0, 0);
  695.  
  696.         sprintf(label, "%s:   No File", DVIPAGE_LABEL);
  697.         window_set(disp_frame,
  698.           FRAME_LABEL, label,
  699.           0);
  700.     }
  701.     else
  702.     {
  703.         pw_cover(pw, 0, 0,
  704.           (int)window_get(canvas, WIN_WIDTH),
  705.           (int)window_get(canvas, WIN_HEIGHT),
  706.           PIX_SRC, sample_pr, -offset_x, -offset_y);
  707.  
  708.         sprintf(label, "%s:   File \"%s\"   %s %d",
  709.           DVIPAGE_LABEL, filename,
  710.           (last_sheet && disp_sheet >= last_sheet-1)?
  711.           "Last page" : "Page",
  712.           disp_page);
  713.         window_set(disp_frame,
  714.           FRAME_LABEL, label,
  715.           0);
  716.     }
  717. }
  718.  
  719. /*
  720.  * page_event:
  721.  *    Called whenever an input event arrives at the window.
  722.  *    Controls panning of the page, turning to the next page,
  723.  *    and reloading a new file.
  724.  */
  725.  
  726. Notify_value
  727. page_event(canvas, event, arg)
  728. Window canvas;
  729. Event *event;
  730. caddr_t arg;
  731. {
  732.     Pixwin *pw;
  733.     int e;
  734.     int pp;
  735.     bool page_or_sheet;
  736.     static int num = 0;
  737.     static bool valid_num = FALSE;
  738.     bool keep_num;
  739.     char *extension;
  740.     char command[STRSIZE];
  741.     double x, y;
  742.  
  743.     if(event_is_up(event))
  744.         return;
  745.  
  746.     pw = canvas_pixwin(canvas);
  747.  
  748.     keep_num = FALSE;
  749.  
  750.     if(verbose & DEBUG_SHEET)
  751.         fprintf(stderr, "page_event: num = %d @ %d\n", num, valid_num);
  752.  
  753.     /*
  754.      * If there is a call for a menu, then translate that into
  755.      * a command character.
  756.      */
  757.     if((e = event_id(event)) == MS_RIGHT)
  758.         if((e = page_menu(canvas, pw, event)) == 0)
  759.             return;
  760.  
  761.     switch(e)
  762.     {
  763.     case MS_LEFT:
  764.         page_magnify(canvas, pw, event);
  765.         break;
  766.  
  767.     case MS_MIDDLE:
  768.         page_pan(canvas, pw, event);
  769.         break;
  770.  
  771.     default:
  772.         if(e >= '0' && e <= '9')
  773.             num = num * 10 + e - '0';
  774.         else if(e == DEL || e == Control('H'))
  775.             num = num / 10;
  776.         else
  777.             break;
  778.  
  779.         keep_num = TRUE;
  780.         valid_num = TRUE;
  781.  
  782.         break;
  783.  
  784.     case '\r':        /* Next page */
  785.     case 'n':
  786.     case ' ':
  787.     case '+':
  788.         if(! valid_num)
  789.             num = 1;
  790.         if(! goto_sheet(disp_sheet + num))
  791.             break;
  792.  
  793.         process_page(RASTERISE);
  794.         offset_x = start_x / sampling;
  795.         offset_y = start_y / sampling;
  796.         page_paint(canvas, pw, 0);
  797.  
  798.         break;
  799.  
  800.     case '\n':        /* Previous page */
  801.     case 'p':
  802.     case '-':
  803.         if(! valid_num)
  804.             num = 1;
  805.         if(! goto_sheet(disp_sheet - num))
  806.             break;
  807.  
  808.         process_page(RASTERISE);
  809.         offset_x = start_x / sampling;
  810.         offset_y = start_y / sampling;
  811.         page_paint(canvas, pw, 0);
  812.  
  813.         break;
  814.  
  815.     case '_':
  816.         num = 1;
  817.         valid_num = TRUE;
  818.         /* FALLTHROUGH */
  819.  
  820.     case 'G':
  821.         if(! valid_num)
  822.             num = LAST_PAGE;
  823.  
  824.         if(! goto_sheet(num))
  825.             break;
  826.  
  827.         process_page(RASTERISE);
  828.         offset_x = start_x / sampling;
  829.         offset_y = start_y / sampling;
  830.         page_paint(canvas, pw, 0);
  831.  
  832.         break;
  833.  
  834.     case 'g':
  835.         if(! valid_num)
  836.             num = LAST_PAGE;
  837.  
  838.         if(! goto_page(num))
  839.             break;
  840.  
  841.         process_page(RASTERISE);
  842.         offset_x = start_x / sampling;
  843.         offset_y = start_y / sampling;
  844.         page_paint(canvas, pw, 0);
  845.  
  846.         break;
  847.  
  848.     case 'h':        /* Home page */
  849.         offset_x = start_x / sampling;
  850.         offset_y = start_y / sampling;
  851.         page_paint(canvas, pw, 0);
  852.         break;
  853.  
  854.     case 'l':        /* Left page */
  855.         offset_x -= 200;
  856.         page_paint(canvas, pw, 0);
  857.         break;
  858.  
  859.     case 'r':        /* Right page */
  860.         offset_x += 200;
  861.         page_paint(canvas, pw, 0);
  862.         break;
  863.  
  864.     case 'u':        /* Up page */
  865.         offset_y -= 300;
  866.         page_paint(canvas, pw, 0);
  867.         break;
  868.  
  869.     case 'd':        /* Down page */
  870.         offset_y += 300;
  871.         page_paint(canvas, pw, 0);
  872.         break;
  873.  
  874.         
  875.     case 'm':        /* Mark margins */
  876.         start_x = offset_x * sampling;
  877.         start_y = offset_y * sampling;
  878.         break;
  879.  
  880.     case 'M':        /* Set margins */
  881.         x = ((double)start_x / resolution);
  882.         y = ((double)start_y / resolution);
  883.         if(! doubles_prompt(1152/2, 900/2,
  884.           "left margin: (inches) ", &x,
  885.           "top margin: (inches)  ", &y,
  886.           0))
  887.             break;
  888.         start_x = (int)(x * resolution);
  889.         start_y = (int)(y * resolution);
  890.         offset_x = start_x / sampling;
  891.         offset_y = start_y / sampling;
  892.         page_paint(canvas, pw, 0);
  893.         break;
  894.  
  895.     case '*':
  896.     case '!':
  897.     case '@':
  898.     case '#':
  899.     case '$':
  900.     case '%':
  901.     case '^':
  902.         valid_num = TRUE;
  903.         if(e == '*')
  904.             num = (mono ?
  905.               DEFAULT_MONO_SAMPLING : DEFAULT_COLOUR_SAMPLING);
  906.         else if(e == '!')
  907.             num = 1;
  908.         else if(e == '@')
  909.             num = 2;
  910.         else if(e == '#')
  911.             num = 3;
  912.         else if(e == '$')
  913.             num = 4;
  914.         else if(e == '%')
  915.             num = 5;
  916.         else
  917.             valid_num = FALSE;
  918.         /* FALLTHROUGH */
  919.  
  920.     case 's':
  921.         if(mono)
  922.             break;
  923.         if(! valid_num || (num < 1 || num > 5))
  924.             sampling = DEFAULT_COLOUR_SAMPLING;
  925.         else
  926.             sampling = num;
  927.  
  928.         sample_page();
  929.         offset_x = start_x / sampling;
  930.         offset_y = start_y / sampling;
  931.         page_paint(canvas, pw, 0);
  932.         break;
  933.  
  934.     case 'S':
  935.         if(mono)
  936.             break;
  937.         if(! integers_prompt(1152/2, 900/2,
  938.           "sampling: (1, 2, 3, 4) ", &sampling,
  939.           0))
  940.             break;
  941.         if(sampling < 1 || sampling > 5)
  942.             sampling = DEFAULT_COLOUR_SAMPLING;
  943.  
  944.         sample_page();
  945.         offset_x = start_x / sampling;
  946.         offset_y = start_y / sampling;
  947.         page_paint(canvas, pw, 0);
  948.         break;
  949.  
  950.     case 'x':
  951.         if(valid_num)
  952.             mag_size_x = num;
  953.         else
  954.             mag_size_x = DEFAULT_MAG_SIZE_X;
  955.         break;
  956.  
  957.     case 'y':
  958.         if(valid_num)
  959.             mag_size_y = num;
  960.         else
  961.             mag_size_y = DEFAULT_MAG_SIZE_Y;
  962.         break;
  963.  
  964.     case 'X':
  965.     case 'Y':
  966.         if(mono)
  967.             break;
  968.         if(! integers_prompt(1152/2, 900/2,
  969.           "magnifier size (x) : ", &mag_size_x,
  970.           "magnifier size (y) : ", &mag_size_y,
  971.           0))
  972.             break;
  973.         break;
  974.  
  975.     case '[':
  976.         mag_size_x = 128;
  977.         mag_size_y = 64;
  978.         break;
  979.  
  980.     case ']':
  981.         mag_size_x = 128;
  982.         mag_size_y = 128;
  983.         break;
  984.  
  985.     case '{':
  986.         mag_size_x = 256;
  987.         mag_size_y = 128;
  988.         break;
  989.  
  990.     case '}':
  991.         mag_size_x = 256;
  992.         mag_size_y = 256;
  993.         break;
  994.  
  995.     case '(':
  996.         mag_size_x = 512;
  997.         mag_size_y = 256;
  998.         break;
  999.  
  1000.     case ')':
  1001.         mag_size_x = 512;
  1002.         mag_size_y = 512;
  1003.         break;
  1004.  
  1005.     case 'b':
  1006.         if(valid_num)
  1007.             mag_border = num;
  1008.         else
  1009.             mag_border = DEFAULT_MAG_BORDER;
  1010.         break;
  1011.  
  1012.     case 'F':
  1013.         if(! strings_prompt(1152/2, 900/2,
  1014.           "Directory: ", directory,
  1015.           "Filename:  ", filename,
  1016.           0))
  1017.             break;
  1018.  
  1019.         /*
  1020.          * Build the whole pathname.
  1021.          */
  1022.         if(directory[0] != '\0')
  1023.         {
  1024.             strcpy(pathname, directory);
  1025.             if(pathname[strlen(pathname)-1] != '/')
  1026.                 strcat(pathname, "/");
  1027.             strcat(pathname, filename);
  1028.         }
  1029.         else
  1030.             strcpy(pathname, filename);
  1031.  
  1032.         /*
  1033.          * If the filename has no extension, or if it
  1034.          * has an extension and it is not '.dvi' then
  1035.          * cat .dvi onto the filename.
  1036.          */
  1037.         if((extension = rindex(pathname, '.')) == NULL ||
  1038.           strcmp(extension, ".dvi") != 0)
  1039.             strcat(pathname, ".dvi");
  1040.  
  1041.         sprintf(label, "%s:   Opening file \"%s\"",
  1042.           DVIPAGE_LABEL, filename);
  1043.         window_set(disp_frame,
  1044.           FRAME_LABEL, label,
  1045.           0);
  1046.         close_dvi_file();
  1047.         if(init_dvi_file())
  1048.         {
  1049.             process_page(RASTERISE);
  1050.             offset_x = start_x / sampling;
  1051.             offset_y = start_y / sampling;
  1052.             page_paint(canvas, pw, 0);
  1053.         }
  1054.         break;
  1055.  
  1056.     case 'R':        /* Reopen file */
  1057.         sprintf(label, "%s:   Reopening file \"%s\"",
  1058.           DVIPAGE_LABEL, filename);
  1059.         window_set(disp_frame,
  1060.           FRAME_LABEL, label,
  1061.           0);
  1062.         if(valid_num)
  1063.         {
  1064.             pp = num;
  1065.             page_or_sheet = TRUE;
  1066.         }
  1067.         else
  1068.         {
  1069.             pp = disp_sheet;
  1070.             page_or_sheet = FALSE;
  1071.         }
  1072.         close_dvi_file();
  1073.         if(init_dvi_file())
  1074.         {
  1075.             if(page_or_sheet)
  1076.             {
  1077.                 if(! goto_page(pp))
  1078.                     (void)goto_sheet(1);
  1079.             }
  1080.             else
  1081.             {
  1082.                 if(! goto_sheet(pp))
  1083.                     (void)goto_sheet(1);
  1084.             }
  1085.  
  1086.             process_page(RASTERISE);
  1087.             offset_x = start_x / sampling;
  1088.             offset_y = start_y / sampling;
  1089.             page_paint(canvas, pw, 0);
  1090.         }
  1091.         break;
  1092.  
  1093.     case 'P':
  1094.         sprintf(command, print_page_spooler,
  1095.           disp_page, disp_page, pathname);
  1096.         if(verbose & DEBUG_PRINTER)
  1097.             fprintf(stderr, "Printer command '%s'\n", command);
  1098.         system(command);
  1099.         break;
  1100.  
  1101.     case Control('P'):
  1102.         sprintf(command, print_spooler, pathname);
  1103.         if(verbose & DEBUG_PRINTER)
  1104.             fprintf(stderr, "Printer command '%s'\n", command);
  1105.         system(command);
  1106.         break;
  1107.  
  1108.     case 'w':
  1109.         show_page_frame = ! show_page_frame;
  1110.  
  1111.         if(goto_sheet(disp_sheet))
  1112.         {
  1113.             process_page(RASTERISE);
  1114.             offset_x = start_x / sampling;
  1115.             offset_y = start_y / sampling;
  1116.             page_paint(canvas, pw, 0);
  1117.         }
  1118.  
  1119.         break;
  1120.  
  1121.     case 'v':
  1122.         if(valid_num)
  1123.             verbose = num;
  1124.         else
  1125.             verbose = 0;
  1126.         break;
  1127.  
  1128.     case 'Q':
  1129.         exit();
  1130.     }
  1131.  
  1132.     if(! keep_num)
  1133.     {
  1134.         num = 0;
  1135.         valid_num = FALSE;
  1136.     }
  1137.  
  1138.     if(verbose & DEBUG_SHEET)
  1139.         fprintf(stderr, "end__event: num = %d @ %d\n", num, valid_num);
  1140. }
  1141.  
  1142. /*
  1143.  * page_menu:
  1144.  *    Displays a menu in response to MS_RIGHT, returns a character
  1145.  *    code to calling function to effect action.
  1146.  */
  1147.  
  1148. int
  1149. page_menu(canvas, pw, event)
  1150. Canvas canvas;
  1151. Pixwin *pw;
  1152. Event *event;
  1153. {
  1154.     static Menu menu = NULL;
  1155.     int action;
  1156.  
  1157.     if(! menu)
  1158.     {
  1159.         /*
  1160.          * Return values from this menu are passed to the
  1161.          * event procedure, and the codes here must match
  1162.          * codes in that function.
  1163.          */
  1164.         menu = menu_create(
  1165.           MENU_ITEM,
  1166.             MENU_STRING, "Next Page",
  1167.             MENU_VALUE, 'n',
  1168.             0,
  1169.           MENU_ITEM,
  1170.             MENU_STRING, "Previous Page",
  1171.             MENU_VALUE, 'p',
  1172.             0,
  1173.           MENU_ITEM,
  1174.             MENU_STRING, "First Page",
  1175.             MENU_VALUE, '_',
  1176.             0,
  1177.           MENU_ITEM,
  1178.             MENU_STRING, "Last Page",
  1179.             MENU_VALUE, 'G',
  1180.             0,
  1181.           MENU_ITEM,
  1182.             MENU_STRING, "Sampling",
  1183.             MENU_PULLRIGHT, menu_create(
  1184.               MENU_ITEM,
  1185.             MENU_STRING, "Default Sampling",
  1186.             MENU_VALUE, '%',
  1187.             0,
  1188.               MENU_ITEM,
  1189.             MENU_STRING, "No Sampling",
  1190.             MENU_VALUE, '!',
  1191.             0,
  1192.               MENU_ITEM,
  1193.             MENU_STRING, "2:1 Sampling",
  1194.             MENU_VALUE, '@',
  1195.             0,
  1196.               MENU_ITEM,
  1197.             MENU_STRING, "3:1 Sampling",
  1198.             MENU_VALUE, '#',
  1199.             0,
  1200.               MENU_ITEM,
  1201.             MENU_STRING, "4:1 Sampling",
  1202.             MENU_VALUE, '$',
  1203.             0,
  1204.               0),
  1205.             0,
  1206.           MENU_ITEM,
  1207.             MENU_STRING, "Magnifier",
  1208.             MENU_PULLRIGHT, menu_create(
  1209.               MENU_ITEM,
  1210.             MENU_STRING, "128 x 64",
  1211.             MENU_VALUE, '[',
  1212.             0,
  1213.               MENU_ITEM,
  1214.             MENU_STRING, "128 x 128",
  1215.             MENU_VALUE, ']',
  1216.             0,
  1217.               MENU_ITEM,
  1218.             MENU_STRING, "256 x 128",
  1219.             MENU_VALUE, '{',
  1220.             0,
  1221.               MENU_ITEM,
  1222.             MENU_STRING, "256 x 256",
  1223.             MENU_VALUE, '}',
  1224.             0,
  1225.               MENU_ITEM,
  1226.             MENU_STRING, "512 x 256",
  1227.             MENU_VALUE, '(',
  1228.             0,
  1229.               MENU_ITEM,
  1230.             MENU_STRING, "512 x 512",
  1231.             MENU_VALUE, ')',
  1232.             0,
  1233.               0),
  1234.             0,
  1235.           MENU_ITEM,
  1236.             MENU_STRING, "Reopen DVI file",
  1237.             MENU_VALUE, 'R',
  1238.             0,
  1239.           MENU_ITEM,
  1240.             MENU_STRING, "New DVI file",
  1241.             MENU_VALUE, 'F',
  1242.             0,
  1243. /*          MENU_ITEM,
  1244.             MENU_STRING, "Print Page",
  1245.             MENU_VALUE, 'P',
  1246.             0,
  1247.           MENU_ITEM,
  1248.             MENU_STRING, "Print Document",
  1249.             MENU_VALUE, Control('P'),
  1250.             0, */
  1251.           MENU_ITEM,
  1252.             MENU_STRING, "Quit",
  1253.             MENU_VALUE, 'Q',
  1254.             0,
  1255.           0);
  1256.     }
  1257.  
  1258.     return (int)menu_show(menu, canvas, event, 0);
  1259. }
  1260.  
  1261. /*
  1262.  * page_magnify:
  1263.  *    Pops up magnified region (only if sampling != 1).
  1264.  *    Currently unimplemented.
  1265.  */
  1266.  
  1267. void
  1268. page_magnify(canvas, pw, event)
  1269. Canvas canvas;
  1270. Pixwin *pw;
  1271. Event *event;
  1272. {
  1273.     Rect r;
  1274.     int w, h;
  1275.     double scale_x, scale_y;
  1276.     int sample_w, sample_h;
  1277.     int new_sample_x, new_sample_y;
  1278.     int delta_x, delta_y;
  1279.     int sample_x, sample_y;
  1280.     int dst_x, dst_y;
  1281.     int page_x, page_y;
  1282.     int old_cursor_op;
  1283.     bool first_time = TRUE;
  1284.     int win_x, win_y;
  1285. #ifdef GOBBLE_MAGNIFY
  1286.     int ninputs, canvasfd;
  1287. #endif GOBBLE_MAGNIFY
  1288.  
  1289.     if(sampling == 1 || sample_pr == NULL)
  1290.         return;
  1291.  
  1292.     if(mag_size_x < 4)
  1293.         mag_size_x = 4;
  1294.     if(mag_size_y < 4)
  1295.         mag_size_y = 4;
  1296.     if(mag_size_x > sample_pr->pr_width)
  1297.         mag_size_x = sample_pr->pr_width;
  1298.     if(mag_size_y > sample_pr->pr_height)
  1299.         mag_size_y = sample_pr->pr_height;
  1300.     if(mag_border < 0)
  1301.         mag_border = 0;
  1302.     if(mag_border > 8)
  1303.         mag_border = 8;
  1304.  
  1305.     /*
  1306.      * Get Lock rect.
  1307.      */
  1308.     r.r_left = 0;
  1309.     r.r_top = 0;
  1310.     r.r_width = (int)window_get(canvas, WIN_WIDTH);
  1311.     r.r_height = (int)window_get(canvas, WIN_HEIGHT);
  1312.  
  1313.     /*
  1314.      * Precompute some window sizes.
  1315.      */
  1316.     w = sample_pr->pr_width;
  1317.     h = sample_pr->pr_height;
  1318.     switch(sampling)
  1319.     {
  1320.     case 2:
  1321.         scale_x = 2.0;
  1322.         scale_y = 2.0;
  1323.         break;
  1324.  
  1325.     case 3:
  1326.         scale_x = 8.0 / 3.0;
  1327.         scale_y = 3.0;
  1328.         break;
  1329.  
  1330.     case 4:
  1331.         scale_x = 4.0;
  1332.         scale_y = 4.0;
  1333.         break;
  1334.  
  1335.     case 5:
  1336.         scale_x = 8.0/3.0;
  1337.         scale_y = 4.0;
  1338.         break;
  1339.  
  1340.     default:
  1341.         return;
  1342.     }
  1343.     sample_w = mag_size_x / scale_x;
  1344.     sample_h = mag_size_y / scale_y;
  1345.  
  1346.     if(verbose & DEBUG_MAGNIFY)
  1347.         fprintf(stderr, "page_magnify: scale %lf %lf; %d %d -> %d %d\n",
  1348.           scale_x, scale_y, sample_w, sample_h, mag_size_x, mag_size_y);
  1349.  
  1350.     /*
  1351.      * Remove the cursor
  1352.      */
  1353.     old_cursor_op = (int)cursor_get(hand_cursor, CURSOR_OP);
  1354.     cursor_set(hand_cursor, CURSOR_OP, PIX_DST, 0);
  1355.     window_set(canvas, WIN_CURSOR, hand_cursor, 0);
  1356.  
  1357.     /*
  1358.      * Grab all input
  1359.      */
  1360.     window_set(canvas, WIN_GRAB_ALL_INPUT, TRUE, 0);
  1361. #ifdef GOBBLE_MAGNIFY
  1362.     canvasfd = (int)window_get(canvas, WIN_FD);
  1363. #endif GOBBLE_MAGNIFY
  1364.  
  1365.     /*
  1366.      * Loop until up mouse.
  1367.      */
  1368.     sample_x = MAXINT;
  1369.     sample_y = MAXINT;
  1370.     while(! event_is_up(event))
  1371.     {
  1372.         /*
  1373.          * Compute the region which will be magnified.
  1374.          */
  1375.         new_sample_x =
  1376.           Range(0, event_x(event)-offset_x-sample_w/2, w-sample_w);
  1377.         new_sample_y =
  1378.           Range(0, event_y(event)-offset_y-sample_h/2, h-sample_h);
  1379.  
  1380.         /*
  1381.          * See how this differs from last magnified region.
  1382.          */
  1383.         delta_x = new_sample_x - sample_x;
  1384.         delta_y = new_sample_y - sample_y;
  1385.  
  1386.         /*
  1387.          * Lock
  1388.          */
  1389.         pw_lock(pw, &r);
  1390.  
  1391.         if(! first_time)
  1392.         {
  1393.             if(verbose & DEBUG_MAGNIFY)
  1394.                 fprintf(stderr, " covering with %d %d\n",
  1395.                   delta_x, delta_y);
  1396.  
  1397.             /*
  1398.              * Paint those portions of the image which were
  1399.              * covered by the last magnifier, and exposed now.
  1400.              * We could just paint the entire patch, but this
  1401.              * gives unpleasant flashing when moving the window.
  1402.              */
  1403.             if(delta_x > 0)
  1404.                 pw_cover(pw, win_x, win_y,
  1405.                   delta_x, mag_size_y,
  1406.                   PIX_SRC, sample_pr, dst_x, dst_y);
  1407.             else if(delta_x < 0)
  1408.                 pw_cover(pw, win_x+mag_size_x+delta_x, win_y,
  1409.                   -delta_x, mag_size_y,
  1410.                   PIX_SRC, sample_pr,
  1411.                   dst_x+mag_size_x+delta_x, dst_y);
  1412.             if(delta_y > 0)
  1413.                 pw_cover(pw, win_x, win_y,
  1414.                   mag_size_x, delta_y,
  1415.                   PIX_SRC, sample_pr, dst_x, dst_y);
  1416.             else if(delta_y < 0)
  1417.                 pw_cover(pw, win_x, win_y+mag_size_y+delta_y,
  1418.                   mag_size_x, -delta_y,
  1419.                   PIX_SRC, sample_pr,
  1420.                   dst_x, dst_y+mag_size_y+delta_y);
  1421.         }
  1422.         else
  1423.             first_time = FALSE;
  1424.  
  1425.         /*
  1426.          * Compute the new destination and window positions
  1427.          * for the new magnified region.
  1428.          */
  1429.         sample_x = new_sample_x;
  1430.         sample_y = new_sample_y;
  1431.         dst_x = sample_x - (mag_size_x - sample_w)/2;
  1432.         dst_y = sample_y - (mag_size_y - sample_h)/2;
  1433.         win_x = dst_x + offset_x;
  1434.         win_y = dst_y + offset_y;
  1435.         page_x = sample_x * scale_x;
  1436.         page_y = sample_y * scale_y;
  1437.  
  1438.         if(verbose & DEBUG_MAGNIFY)
  1439.             fprintf(stderr, " painting at %d %d from %d %d\n",
  1440.               dst_x, dst_y, page_x, page_y);
  1441.  
  1442.         /*
  1443.          * Display the magnified region.
  1444.          */
  1445.         pw_write(pw, win_x, win_y, mag_size_x, mag_size_y,
  1446.           PIX_SRC, page_pr, page_x, page_y);
  1447.         if(mag_border)
  1448.             pw_rect(pw, win_x, win_y, mag_size_x, mag_size_y,
  1449.               mag_border, PIX_SRC, -1);
  1450.  
  1451.         /*
  1452.          * Unlock
  1453.          */
  1454.         pw_unlock(pw);
  1455.  
  1456.         /*
  1457.          * Read another event.
  1458.          */
  1459.         window_read_event(canvas, event);
  1460. #ifdef GOBBLE_MAGNIFY
  1461.         if(ioctl(canvasfd, FIONREAD, &ninputs) == 0)
  1462.             while(ninputs >= sizeof(Event) &&
  1463.               window_read_event(canvas, event) == 0 &&
  1464.               ! event_is_up(event))
  1465.                 ninputs -= sizeof(Event);
  1466. #endif GOBBLE_MAGNIFY
  1467.     }
  1468.  
  1469.     /*
  1470.      * Ungrab all input.
  1471.      */
  1472.     window_set(canvas, WIN_GRAB_ALL_INPUT, FALSE, 0);
  1473.  
  1474.     /*
  1475.      * Repaint
  1476.      */
  1477.     pw_cover(pw, win_x, win_y, mag_size_x, mag_size_y,
  1478.       PIX_SRC, sample_pr, dst_x, dst_y);
  1479.  
  1480.     /*
  1481.      * Restore the cursor.
  1482.      */
  1483.     cursor_set(hand_cursor, CURSOR_OP, old_cursor_op, 0);
  1484.     window_set(canvas, WIN_CURSOR, hand_cursor, 0);
  1485. }
  1486.  
  1487. /*
  1488.  * page_pan:
  1489.  *    Pans page within screen.
  1490.  */
  1491.  
  1492. void
  1493. page_pan(canvas, pw, event)
  1494. Canvas canvas;
  1495. Pixwin *pw;
  1496. Event *event;
  1497. {
  1498.     int x, y;
  1499.     int dx, dy;
  1500. #ifdef GOBBLE_PAN
  1501.     int ninputs, canvasfd;
  1502. #endif GOBBLE_PAN
  1503.  
  1504.  
  1505.     if(sample_pr == NULL)
  1506.         return;
  1507.  
  1508.     window_set(canvas, WIN_GRAB_ALL_INPUT, TRUE, 0);
  1509. #ifdef GOBBLE_PAN
  1510.     canvasfd = (int)window_get(canvas, WIN_FD);
  1511. #endif GOBBLE_PAN
  1512.  
  1513.     do
  1514.     {
  1515.         x = event_x(event);
  1516.         y = event_y(event);
  1517.  
  1518.         window_read_event(canvas, event);
  1519. #ifdef GOBBLE_PAN
  1520.         if(ioctl(canvasfd, FIONREAD, &ninputs) == 0)
  1521.             while(ninputs >= sizeof(Event) &&
  1522.               window_read_event(canvas, event) == 0 &&
  1523.               ! event_is_up(event))
  1524.                 ninputs -= sizeof(Event);
  1525. #endif GOBBLE_PAN
  1526.  
  1527.         dx = event_x(event) - x;
  1528.         dy = event_y(event) - y;
  1529.  
  1530.         if(dx != 0 || dy != 0)
  1531.         {
  1532.             offset_x += dx;
  1533.             offset_y += dy;
  1534.  
  1535.             pw_cover(pw, 0, 0,
  1536.               (int)window_get(canvas, WIN_WIDTH),
  1537.               (int)window_get(canvas, WIN_HEIGHT),
  1538.               PIX_SRC, sample_pr, -offset_x, -offset_y);
  1539.         }
  1540.     }
  1541.     while(! event_is_up(event));
  1542.  
  1543.     window_set(canvas, WIN_GRAB_ALL_INPUT, FALSE, 0);
  1544. }
  1545.  
  1546. /*
  1547.  * goto_sheet:
  1548.  *    Opens requested sheet on screen.
  1549.  */
  1550.  
  1551. bool
  1552. goto_sheet(new_sheet)
  1553. int new_sheet;
  1554. {
  1555.     if(! check_dvi_file())
  1556.         return FALSE;
  1557.  
  1558.     if(verbose & DEBUG_SHEET)
  1559.         fprintf(stderr, "goto_sheet(%d)\n", new_sheet);
  1560.  
  1561.     /*
  1562.      * Check against page limits.
  1563.      */
  1564.     if(new_sheet <= 0)
  1565.     {
  1566.         message("Attempt to go to sheet %d.", new_sheet);
  1567.         return FALSE;
  1568.     }
  1569.  
  1570.     /*
  1571.      * Are we already at the desired page ?
  1572.      */
  1573.     if(file_sheet == new_sheet)
  1574.         return TRUE;
  1575.  
  1576.     /*
  1577.      * Do we already know where the page is ?
  1578.      */
  1579.     if(new_sheet < MAX_SHEETS && new_sheet <= last_known_sheet)
  1580.     {
  1581.         fseek(dvifp, sheet_table[new_sheet], 0);
  1582.         file_sheet = new_sheet;
  1583.         return TRUE;
  1584.     }
  1585.  
  1586.     /*
  1587.      * Can't find it directly in the table:
  1588.      * Go to the last known sheet...
  1589.      */
  1590.     file_sheet = last_known_sheet;
  1591.     fseek(dvifp, sheet_table[file_sheet], 0);
  1592.  
  1593.     /*
  1594.      * Skip through the rest of the pages to the new page.
  1595.      */
  1596.     while(file_sheet < new_sheet)
  1597.     {
  1598.         /*
  1599.          * Check for last page:
  1600.          * Last page is always returned.
  1601.          */
  1602.         if(last_sheet && file_sheet >= last_sheet)
  1603.         {
  1604.             file_sheet = last_sheet - 1;
  1605.             fseek(dvifp, sheet_table[file_sheet], 0);
  1606.             return TRUE;
  1607.         }
  1608.  
  1609.         /*
  1610.          * Otherwise, skip this page and look at the next.
  1611.          */
  1612.         process_page(SKIP);
  1613.     }
  1614.     return TRUE;
  1615. }
  1616.  
  1617. /*
  1618.  * goto_page:
  1619.  *    Opens requested page on screen.
  1620.  */
  1621.  
  1622. bool
  1623. goto_page(new_page)
  1624. int new_page;
  1625. {
  1626.     int sheet;
  1627.  
  1628.     if(! check_dvi_file())
  1629.         return FALSE;
  1630.  
  1631.     if(verbose & DEBUG_SHEET)
  1632.         fprintf(stderr, "goto_page(%d)\n", new_page);
  1633.  
  1634.     /*
  1635.      * Search for page in the table.
  1636.      */
  1637.     for(sheet = 1; sheet < last_known_sheet; sheet++)
  1638.     {
  1639.         if(sheet_page[sheet] == new_page)
  1640.         {
  1641.             file_sheet = sheet;
  1642.             fseek(dvifp, sheet_table[file_sheet], 0);
  1643.             return TRUE;
  1644.         }
  1645.     }
  1646.  
  1647.     /*
  1648.      * Can't find it directly in the table:
  1649.      * Go to the last known sheet...
  1650.      */
  1651.     file_sheet = last_known_sheet;
  1652.     fseek(dvifp, sheet_table[file_sheet], 0);
  1653.  
  1654.     /*
  1655.      * Skip through the rest of the pages to the new page.
  1656.      */
  1657.     for( ; ; )
  1658.     {
  1659.         /*
  1660.          * Check for last page:
  1661.          */
  1662.         if(last_sheet && file_sheet >= last_sheet)
  1663.         {
  1664.             if(new_page == LAST_PAGE)
  1665.             {
  1666.                 file_sheet = last_sheet - 1;
  1667.                 fseek(dvifp, sheet_table[file_sheet], 0);
  1668.                 return TRUE;
  1669.             }
  1670.             else
  1671.                 return FALSE;
  1672.         }
  1673.  
  1674.         /*
  1675.          * Otherwise, examine this page.
  1676.          */
  1677.         sheet = file_sheet;
  1678.         process_page(SKIP);
  1679.  
  1680.         /*
  1681.          * If this was the page, go back,
  1682.          * and return it.
  1683.          */
  1684.         if(sheet_page[sheet] == new_page)
  1685.         {
  1686.             file_sheet = sheet;
  1687.             fseek(dvifp, sheet_table[file_sheet], 0);
  1688.             return TRUE;
  1689.         }
  1690.     }
  1691. }
  1692.  
  1693. /*
  1694.  * DVI file functions.
  1695.  * ==================
  1696.  */
  1697.  
  1698. /*
  1699.  * init_dvi_file:
  1700.  *    Opens the dvi file, and checks for valid codes etc.
  1701.  *    Reads the postamble (if enabled)
  1702.  *    Leaves the file pointer at the start of the first page.
  1703.  */
  1704.  
  1705. bool
  1706. init_dvi_file()
  1707. {
  1708.     int i;
  1709.  
  1710.     /*
  1711.      * Open the file; close-on-exec.
  1712.      */
  1713.     if((dvifp = fopen(pathname, "r")) == NULL)
  1714.     {
  1715.         message("Cant open file %s", pathname);
  1716.         return FALSE;
  1717.     }
  1718.     fcntl(fileno(dvifp),  F_SETFD,  1);
  1719.  
  1720.     /*
  1721.      * Read the magic number and version number
  1722.      */
  1723.     if((i = get_unsigned(dvifp, 1)) != PRE)
  1724.     {
  1725.         message("%s: not a dvi file.", filename);
  1726.         fclose(dvifp);
  1727.         return FALSE;
  1728.     }
  1729.     if((i = get_signed(dvifp, 1)) != DVIFORMAT)
  1730.     {
  1731.         message("%s: dvi format %d not supported.", filename, i);
  1732.         fclose(dvifp);
  1733.         return FALSE;
  1734.     }
  1735.  
  1736.     /*
  1737.      * Make a note of the access time.
  1738.      */
  1739.     if(fstat(fileno(dvifp), &stat_buf) == 0)
  1740.     {
  1741.         mtime = stat_buf.st_mtime;
  1742.     }
  1743.     else
  1744.     {
  1745.         message("%s: dvifile stat failed.", filename);
  1746.         mtime = 0;
  1747.     }
  1748.  
  1749.     if(pre_load)
  1750.     {
  1751.         /*
  1752.          * Load font information from postable.
  1753.          */
  1754.         if(! read_postamble())
  1755.         {
  1756.             fclose(dvifp);
  1757.             return FALSE;
  1758.         }
  1759.  
  1760.         /*
  1761.          * Return to start of first page.
  1762.          */
  1763.         fseek(dvifp, (long)14, 0);
  1764.     }
  1765.     else
  1766.     {
  1767.         /*
  1768.          * Read basic data from preamble.
  1769.          */
  1770.         num = get_unsigned(dvifp, 4);
  1771.         den = get_unsigned(dvifp, 4);
  1772.         mag = get_unsigned(dvifp, 4);
  1773.         hconv = vconv = do_convert(num, den, resolution);
  1774.     }
  1775.  
  1776.     /*
  1777.      * Skip i more bytes of preamble.
  1778.      */
  1779.     i = get_unsigned(dvifp, 1);
  1780.     fseek(dvifp, (long)i, 1);
  1781.  
  1782.     /*
  1783.      * Allocate buffer for the page.
  1784.      */
  1785.     if(! (page_pr = pr_alloc(&page_mpr,
  1786.       (int)(page_w * resolution), (int)(page_h * resolution), 1)))
  1787.     {
  1788.         message("Out of memory for image allocation.");
  1789.         fclose(dvifp);
  1790.         return FALSE;
  1791.     }
  1792.  
  1793.     if(verbose & DEBUG_IMSIZE)
  1794.         fprintf(stderr, "Allocated buffer (%d x %d)\n",
  1795.           page_pr->pr_width, page_pr->pr_height);
  1796.  
  1797.     /*
  1798.      * Set up the page fseek pointer table.
  1799.      * We are now at page 0.
  1800.      */
  1801.     for(i = 0; i < MAX_SHEETS; i++)
  1802.     {
  1803.         sheet_table[i] = 0;
  1804.         sheet_page[i] = BAD_PAGE;
  1805.     }
  1806.     file_sheet = 1;
  1807.     last_sheet = 0;    /* last page == unknown */
  1808.     last_known_sheet = 1;
  1809.     sheet_table[last_known_sheet] = ftell(dvifp);
  1810.  
  1811.     if(verbose & DEBUG_SHEET)
  1812.         fprintf(stderr, "sheet_table[%d] = %d\n",
  1813.           last_known_sheet, ftell(dvifp));
  1814.  
  1815.     return TRUE;
  1816. }
  1817.  
  1818. /*
  1819.  * close_dvi_file:
  1820.  *    Cleans up after reading a file.
  1821.  */
  1822.  
  1823. void
  1824. close_dvi_file()
  1825. {
  1826.     if(dvifp == NULL)
  1827.         return;
  1828.  
  1829.     /*
  1830.      * Get rid of image memory.
  1831.      */
  1832.     sample_pr = pr_free(&sample_mpr);
  1833.     page_pr = pr_free(&page_mpr);
  1834.  
  1835.     /*
  1836.      * close the dvifile.
  1837.      */
  1838.     fclose(dvifp);
  1839.     dvifp = NULL;
  1840.     mtime = 0;
  1841.  
  1842.     /*
  1843.      * Hack the sheet numbers to prevent access to the file.
  1844.      */
  1845.     last_sheet = -1;
  1846.     last_known_sheet = -1;
  1847.  
  1848.     /*
  1849.      * Close the fonts and free up memory.
  1850.      */
  1851.     close_fonts();
  1852. }
  1853.  
  1854. /*
  1855.  * check_dvi_file:
  1856.  *    Checks that this is the same file -- has not been modified since
  1857.  *    it was opened.
  1858.  */
  1859.  
  1860. bool
  1861. check_dvi_file()
  1862. {
  1863.     if(dvifp == NULL)
  1864.     {
  1865.         message("No dvifile open");
  1866.         return FALSE;
  1867.     }
  1868.  
  1869.     if(fstat(fileno(dvifp), &stat_buf) != 0)
  1870.     {
  1871.         message("%s: dvifile fstat failed.", filename);
  1872.         return FALSE;
  1873.     }
  1874.  
  1875.     if(stat_buf.st_mtime != mtime)
  1876.     {
  1877.         message("%s: dvifile modified", filename);
  1878.         return FALSE;
  1879.     }
  1880.  
  1881.     return TRUE;
  1882. }
  1883.  
  1884. /*
  1885.  * read_postamble:
  1886.  *    This  routine  is  used  to  read  in  the  postamble  values.    It
  1887.  *    initializes the magnification and checks  the stack height prior  to
  1888.  *    starting printing the document.
  1889.  *    Returns TRUE unless document cannot be processed.
  1890.  */
  1891.  
  1892. bool
  1893. read_postamble()
  1894. {
  1895.     if(! check_dvi_file())
  1896.         return FALSE;
  1897.  
  1898.     if(! find_postamble_ptr (&postambleptr))
  1899.         return FALSE;
  1900.  
  1901.     if(get_unsigned(dvifp, 1) != POST)
  1902.     {
  1903.         message("%s: bad dvi file: no POST at head of postamble.",
  1904.           filename);
  1905.         return FALSE;
  1906.     }
  1907.  
  1908.     (void)get_unsigned(dvifp, 4); /* discard last page pointer */
  1909.     num = get_unsigned(dvifp, 4);
  1910.     den = get_unsigned(dvifp, 4);
  1911.     mag = get_unsigned(dvifp, 4);
  1912.     hconv = vconv = do_convert(num, den, resolution);
  1913.  
  1914.     (void)get_unsigned(dvifp, 4);    /* height-plus-depth of tallest page */
  1915.     (void)get_unsigned(dvifp, 4);    /* width of widest page */
  1916.  
  1917.     if(get_unsigned(dvifp, 2) >= STACKSIZE)
  1918.     {
  1919.         message("%s: bad dvi file: stack is too large.",
  1920.           filename);
  1921.         return FALSE;
  1922.     }
  1923.  
  1924.     /* last_sheet = */ get_unsigned(dvifp, 2);
  1925.  
  1926.     if(! get_font_def())
  1927.         return FALSE;
  1928.  
  1929.     return TRUE;
  1930. }
  1931.  
  1932. /*
  1933.  * find_postamble_ptr
  1934.  *    Move to the end of the dvifile and find the start of the postamble.
  1935.  */
  1936.  
  1937. bool
  1938. find_postamble_ptr(postambleptr)
  1939. long *postambleptr;
  1940. {
  1941.     int i;
  1942.  
  1943.     fseek(dvifp, (long) 0, 2);
  1944.     *postambleptr = ftell(dvifp) - 4;
  1945.     fseek(dvifp, *postambleptr, 0);
  1946.  
  1947.     for( ; ; )
  1948.     {
  1949.         fseek(dvifp, --(*postambleptr), 0);
  1950.         if(((i = get_unsigned(dvifp, 1)) != 223) && (i != DVIFORMAT))
  1951.         {
  1952.             message("%s: Bad dvi file: bad end of file", filename);
  1953.             return FALSE;
  1954.         }
  1955.         if(i == DVIFORMAT)
  1956.             break;
  1957.     }
  1958.  
  1959.     fseek(dvifp, (*postambleptr) - 4, 0);
  1960.     *postambleptr = get_unsigned(dvifp, 4);
  1961.     fseek(dvifp, *postambleptr, 0);
  1962.  
  1963.     return TRUE;
  1964. }
  1965.  
  1966. /*
  1967.  * process_page:
  1968.  *    Rasterises the next page in the dvifile into page_mpr.
  1969.  *    Leaves the file pointer at the start of the next page.
  1970.  *
  1971.  *    If skip mode is true, then nothing is actually drawn, the commands
  1972.  *    are interpreted only for the side effect of moving the filepointer
  1973.  *    to the next page.
  1974.  */
  1975.  
  1976. bool
  1977. process_page(skip_mode)
  1978. register bool skip_mode;
  1979. {
  1980.     int command;        /* current command */
  1981.     register int i;        /* command parameter; loop index */
  1982.     int k;            /* temporary parameter */
  1983.     int val, val2;      /* temporarys to hold command information*/
  1984.     int w;            /* current horizontal spacing */
  1985.     int x;            /* current horizontal spacing */
  1986.     int y;            /* current vertical spacing */
  1987.     int z;            /* current vertical spacing */
  1988.     int counter[10];
  1989.     int sp;            /* stack pointer */
  1990.     static struct stack_entry stack[STACKSIZE];   /* stack */
  1991.  
  1992.     if(! check_dvi_file())
  1993.         return FALSE;
  1994.  
  1995.     if(verbose & DEBUG_SHEET)
  1996.         fprintf(stderr, "sheet %d starts at %d\n",
  1997.           file_sheet, ftell(dvifp));
  1998.  
  1999.     while((command = get_unsigned(dvifp, 1)) != EOP)
  2000.     {
  2001.         switch(command)
  2002.         {
  2003.  
  2004.         case SET1:
  2005.         case SET2:
  2006.         case SET3:
  2007.         case SET4:
  2008.             val = get_unsigned(dvifp, command-SET1+1);
  2009.             if(! skip_mode)
  2010.                 set_char(val, command);
  2011.             break;
  2012.  
  2013.         case SET_RULE:
  2014.             val = get_unsigned(dvifp, 4);
  2015.             val2 = get_unsigned(dvifp, 4);
  2016.             if(! skip_mode)
  2017.                 set_rule(val, val2, 1);
  2018.             break;
  2019.  
  2020.         case PUT1:
  2021.         case PUT2:
  2022.         case PUT3:
  2023.         case PUT4:
  2024.             val = get_unsigned(dvifp,command-PUT1+1);
  2025.             if(! skip_mode)
  2026.                 set_char(val, command);
  2027.             break;
  2028.  
  2029.         case PUT_RULE:
  2030.             val = get_unsigned(dvifp, 4);
  2031.             val2 = get_unsigned(dvifp, 4);
  2032.             if(! skip_mode)
  2033.                 set_rule(val, val2, 0);
  2034.             break;
  2035.  
  2036.         case NOP:
  2037.             break;
  2038.  
  2039.         case BOP:
  2040.             /*
  2041.              * These are the 10 counters.
  2042.              * Discard previous page pointer.
  2043.              */
  2044.             for(i=0; i<10; i++)
  2045.                 counter[i] = get_unsigned(dvifp, 4);
  2046.             (void)get_unsigned(dvifp, 4);
  2047.  
  2048.             /*
  2049.              * The first counter is the page number.
  2050.              */
  2051.             disp_page = counter[0];
  2052.             if(file_sheet < MAX_SHEETS)
  2053.                 sheet_page[file_sheet] = disp_page;
  2054.  
  2055.             /*
  2056.              * Show what is happening.
  2057.              */
  2058.             sprintf(label, "%s:   File \"%s\"   Page %d   %s",
  2059.               DVIPAGE_LABEL, filename,
  2060.               disp_page, (skip_mode) ? "Skipping" : "Processing");
  2061.             window_set(disp_frame,
  2062.               FRAME_LABEL, label,
  2063.               0);
  2064.  
  2065.             if(! skip_mode)
  2066.             {
  2067.                 /*
  2068.                  * Clear the page
  2069.                  */
  2070.                 pr_rop(page_pr, 0, 0,
  2071.                   page_pr->pr_width, page_pr->pr_height,
  2072.                   PIX_CLR, NULL, 0, 0);
  2073.  
  2074.                 /*
  2075.                  * Mark the edges of the page
  2076.                  */
  2077.                 pr_rect(page_pr, 0, 0,
  2078.                   (int)(page_w * resolution),
  2079.                   (int)(page_h * resolution),
  2080.                   3, PIX_SET, 1);
  2081.  
  2082.                 /*
  2083.                  * Mark the nominal page window.
  2084.                  */
  2085.                 if(show_page_frame)
  2086.                 {
  2087.                     pr_rect(page_pr, 0+origin_x, 0+origin_y,
  2088.                       (int)(page_w*resolution) - 2*origin_x,
  2089.                       (int)(page_h*resolution) - 2*origin_y,
  2090.                       1, PIX_SET, 1);
  2091.                 }
  2092.             }
  2093.  
  2094.             h = v = w = x = y = z = 0;
  2095.             sp = 0;
  2096.             fontptr = NULL;
  2097.             break;
  2098.  
  2099.         case PUSH:
  2100.             if (sp >= STACKSIZE)
  2101.             {
  2102.                 message("%s: Bad dvi file: stack overflow",
  2103.                   filename);
  2104.                 return FALSE;
  2105.             }
  2106.             stack[sp].h = h;
  2107.             stack[sp].v = v;
  2108.             stack[sp].w = w;
  2109.             stack[sp].x = x;
  2110.             stack[sp].y = y;
  2111.             stack[sp].z = z;
  2112.             sp++;
  2113.             break;
  2114.  
  2115.         case POP:
  2116.             --sp;
  2117.             if (sp < 0)
  2118.             {
  2119.                 message("%s: Bad dvi file: stack underflow",
  2120.                   filename);
  2121.                 return FALSE;
  2122.             }
  2123.             h = stack[sp].h;
  2124.             v = stack[sp].v;
  2125.             w = stack[sp].w;
  2126.             x = stack[sp].x;
  2127.             y = stack[sp].y;
  2128.             z = stack[sp].z;
  2129.             break;
  2130.  
  2131.         case RIGHT1:
  2132.         case RIGHT2:
  2133.         case RIGHT3:
  2134.         case RIGHT4:
  2135.             val = get_signed(dvifp,command-RIGHT1+1);
  2136.             if(! skip_mode)
  2137.                 move_over(val);
  2138.             break;
  2139.  
  2140.         case W0:
  2141.             if(! skip_mode)
  2142.                 move_over(w);
  2143.             break;
  2144.  
  2145.         case W1:
  2146.         case W2:
  2147.         case W3:
  2148.         case W4:
  2149.             w = get_signed(dvifp,command-W1+1);
  2150.             if(! skip_mode)
  2151.                 move_over(w);
  2152.             break;
  2153.  
  2154.         case X0:
  2155.             if(! skip_mode)
  2156.                 move_over(x);
  2157.             break;
  2158.  
  2159.         case X1:
  2160.         case X2:
  2161.         case X3:
  2162.         case X4:
  2163.             x = get_signed(dvifp,command-X1+1);
  2164.             if(! skip_mode)
  2165.                 move_over(x);
  2166.             break;
  2167.  
  2168.         case DOWN1:
  2169.         case DOWN2:
  2170.         case DOWN3:
  2171.         case DOWN4:
  2172.             val = get_signed(dvifp,command-DOWN1+1);
  2173.             if(! skip_mode)
  2174.                 move_down(val);
  2175.             break;
  2176.  
  2177.         case Y0:
  2178.             if(! skip_mode)
  2179.                 move_down(y);
  2180.             break;
  2181.  
  2182.         case Y1:
  2183.         case Y2:
  2184.         case Y3:
  2185.         case Y4:
  2186.             y = get_signed(dvifp,command-Y1+1);
  2187.             if(! skip_mode)
  2188.                 move_down(y);
  2189.             break;
  2190.  
  2191.         case Z0:
  2192.             if(! skip_mode)
  2193.                 move_down(z);
  2194.             break;
  2195.  
  2196.         case Z1:
  2197.         case Z2:
  2198.         case Z3:
  2199.         case Z4:
  2200.             z = get_signed(dvifp,command-Z1+1);
  2201.             if(! skip_mode)
  2202.                 move_down(z);
  2203.             break;
  2204.  
  2205.         case FNT1:
  2206.         case FNT2:
  2207.         case FNT3:
  2208.         case FNT4:
  2209.             if(! skip_mode)
  2210.                 set_font_num(
  2211.                   get_unsigned(dvifp,command-FNT1+1));
  2212.             break;
  2213.  
  2214.         case XXX1:
  2215.         case XXX2:
  2216.         case XXX3:
  2217.         case XXX4:
  2218.             k = get_unsigned(dvifp,command-XXX1+1);
  2219.             while(k--)
  2220.                 get_unsigned(dvifp, 1);
  2221.             break;
  2222.  
  2223.         case FNT_DEF1:
  2224.         case FNT_DEF2:
  2225.         case FNT_DEF3:
  2226.         case FNT_DEF4:
  2227.             if(pre_load)
  2228.                 skip_font_def(
  2229.                   get_unsigned(dvifp, command-FNT_DEF1+1));
  2230.             else
  2231.                 if(! read_font_def(
  2232.                   get_unsigned(dvifp, command-FNT_DEF1+1)))
  2233.                     return FALSE;
  2234.             break;
  2235.  
  2236.         case PRE:
  2237.             message(
  2238.   "%s: Bad dvi file: preamble found within main section.",
  2239.               filename);
  2240.             return FALSE;
  2241.  
  2242.         case POST:
  2243.             fseek(dvifp, (long) -1, 1);
  2244.             last_sheet = file_sheet;
  2245.  
  2246.             /*
  2247.              * We have done nothing, so there is no need to
  2248.              * resample the page or increment the page counter.
  2249.              */
  2250.             return FALSE;
  2251.  
  2252.         case POST_POST:
  2253.             message(
  2254.   "%s: Bad dvi file: postpostamble found within main section.",
  2255.               filename);
  2256.             return FALSE;
  2257.  
  2258.         default:
  2259.             if(command >= FONT_00 && command <= FONT_63)
  2260.             {
  2261.                 if(! skip_mode)
  2262.                     set_font_num(command - FONT_00);
  2263.             }
  2264.             else if(command >= SETC_000 && command <= SETC_127)
  2265.             {
  2266.                 if(! skip_mode)
  2267.                     set_char(command - SETC_000, command);
  2268.             }
  2269.             else
  2270.             {
  2271.                 message(
  2272.   "%s: Bad dvi file: undefined command (%d) found.",
  2273.                   filename, command);
  2274.                 return FALSE;
  2275.             }
  2276.         }
  2277.     }
  2278.  
  2279.     /*
  2280.      * End of page.
  2281.      */
  2282.     if(! skip_mode)
  2283.     {
  2284.         /*
  2285.          * Sample the page.
  2286.          */
  2287.         sample_page();
  2288.         disp_sheet = file_sheet;
  2289.     }
  2290.  
  2291.     /*
  2292.      * The file is now at the start of the next page.
  2293.      */
  2294.     file_sheet++;
  2295.     if(file_sheet > last_known_sheet)
  2296.     {
  2297.         if(file_sheet < MAX_SHEETS)
  2298.         {
  2299.             last_known_sheet = file_sheet;
  2300.             sheet_table[file_sheet] = ftell(dvifp);
  2301.         }
  2302.  
  2303.         if(verbose & DEBUG_SHEET)
  2304.             fprintf(stderr, "sheet %d starts at %d\n",
  2305.               file_sheet, ftell(dvifp));
  2306.     }
  2307.  
  2308.     return TRUE;
  2309. }
  2310.  
  2311. /*
  2312.  * Draw and Move Functions.
  2313.  * ========================
  2314.  */
  2315.  
  2316. /*
  2317.  * set_font_num:
  2318.  *    This routine is used to specify the font to be used in printing future
  2319.  *    chars.
  2320.  */
  2321.  
  2322. void
  2323. set_font_num(k)
  2324. int k;
  2325. {
  2326.     for(fontptr = hfontptr; fontptr != NULL; fontptr = fontptr->next)
  2327.     {
  2328.         if(fontptr->k == k)
  2329.         {
  2330.             fontptr->use_count++;
  2331.             return;
  2332.         }
  2333.     }
  2334.  
  2335.     fprintf(stderr, "I have lost a font; this cant happen\n");
  2336.     exit(1);
  2337. }
  2338.  
  2339. /*
  2340.  * set_char:
  2341.  */
  2342.  
  2343. void
  2344. set_char(c, command)
  2345. int c, command;
  2346. {
  2347.     register struct char_entry *ptr;
  2348.  
  2349.     ptr = &(fontptr->ch[c]);
  2350.     hh = Pix_round(h, hconv);
  2351.     vv = Pix_round(v, vconv);
  2352.  
  2353.     if(! ptr->where.isloaded)
  2354.         if(! load_char(fontptr, ptr))
  2355.             return;
  2356.  
  2357.     if(ptr->where.address.pixrectptr)
  2358.         pr_rop(page_pr, hh - ptr->xOffset + origin_x,
  2359.           vv - ptr->yOffset + origin_y,
  2360.           ptr->width, ptr->height, PIX_SRC | PIX_DST,
  2361.           ptr->where.address.pixrectptr, 0, 0);
  2362.  
  2363.     if(command <= SET4)
  2364.         h += ptr->tfmw;
  2365.  
  2366.     return;
  2367. }
  2368.  
  2369. /*
  2370.  * set_rule:
  2371.  *    This routine will draw a rule on the screen
  2372.  */
  2373.  
  2374. void
  2375. set_rule(a, b, Set)
  2376. int a, b;
  2377. bool Set;
  2378. {
  2379.     int ehh, evv;
  2380.  
  2381.     hh = Pix_round(h, hconv);
  2382.     vv = Pix_round(v - a, vconv);
  2383.     ehh = Pix_round(h + b, hconv);
  2384.     evv = Pix_round(v, vconv);
  2385.  
  2386.     if(hh == ehh)
  2387.         ehh++;
  2388.     if(vv == evv)
  2389.         vv--;
  2390.     if((a > 0) && (b > 0))
  2391.         pr_rop(page_pr, hh+origin_x, vv+origin_y,
  2392.           ehh-hh, evv-vv, PIX_SET, NULL, 0, 0);
  2393.     if(Set)
  2394.     {
  2395.         h += b;
  2396. /*        v += a; */
  2397.     }
  2398. }
  2399.  
  2400. /*
  2401.  * move_down:
  2402.  */
  2403.  
  2404. void
  2405. move_down(a)
  2406. int a;
  2407. {
  2408.     v += a;
  2409. }
  2410.  
  2411.  
  2412. /*
  2413.  * move_over:
  2414.  */
  2415.  
  2416. void
  2417. move_over(b)
  2418. int b;
  2419. {
  2420.     h += b;
  2421. }
  2422.